﻿using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Zocono.Infrastructure.Common;
using Zocono.WCS.Domain.DomainRepository;
using Zocono.WCS.Domain.EntityInfo;
using Zocono.WCS.Domain.PlcBytesObject;
using Zocono.WCS.Domain.PlcConnectPoolDomain;
using Zocono.WCS.Domain.ProcessModuleDomain;
using Zocono.WCS.Infrastructure.ApllicationDto.Enums;
using Zocono.WCS.WMSApiDomain.WebApi;

namespace Zocono.WCS.Domain.EquipmentProcessDomain.PlanarGeneralMessage
{
    /// <summary>
    /// 到达下料台（DO）没有任务编码
    /// </summary>
    public class ArriveDoNoTaskCodeService : IPlanarGeneralPlcActionProcessService
    {
        private readonly ILogUtil _LogUtil;
        private readonly IPlcConnectionPool _PlcConnectionPool;
        private readonly IWorkTaskInfoRepository _WorkTaskInfoRepository;
        private readonly IPlcWriteDbInfoRepository _PlcWriteDbInfoRepository;

        public ArriveDoNoTaskCodeService(ILogUtil logUtil
            , IPlcConnectionPool plcConnectionPool
            , IWorkTaskInfoRepository workTaskInfoRepository
            , IPlcWriteDbInfoRepository plcWriteDbInfoRepository)
        {
            _LogUtil = logUtil;
            _PlcConnectionPool = plcConnectionPool;
            _WorkTaskInfoRepository = workTaskInfoRepository;
            _PlcWriteDbInfoRepository = plcWriteDbInfoRepository;
        }
        public async Task ProcessActionMessageAsync(BytesObjectBase plcActionMessage, BytesObjectBase wcsActionMessage, EquipmentDbObject planarEquipmentDbObject/*, BytesObjectBase plcStateMassge*/)
        {
            /*
             * 1. 一注高温浸润空托补给下架托盘到达堆垛机卸载位请求数据
             *     - 2, 0, 堆垛机卸载完成PLC上报托盘到达卸载位请求数据（PLC->WCS),WCS计算目标位置下发。
             * 2. 一注高温浸润完成满托下架托盘到达堆垛机卸载位请求数据
             *     - 1, 0, 堆垛机卸载完成PLC上报托盘到达卸载位请求数据（PLC->WCS),WCS计算目标位置下发。
             * 3. 化成托盘下架到达堆垛机卸载位申请数据
             *     - 1, 0, PLC上报托盘到达装载位（PLC->WCS),WCS执行调度堆垛机业务。
             * 4. 化成NG托盘下架到达堆垛机卸载位申请数据
             *     - 2, 0, PLC上报托盘到达装载位（PLC->WCS),WCS执行调度堆垛机业务。
             */

            /*
             * 处理逻辑
             * 1. 验证plc是否在线
             * 2. 验证当前设备是否报警
             * 3. 验证wcs任务，验证wcs当前子任务(待执行、执行中)，当前子任务已经是SC完成后更新了
             * 4. 组织plc报文，写入plc
             */
            var plcMessage = plcActionMessage as PlanarGeneralPlcActionBO;//Plc的动作报文
            var wcsMessage = wcsActionMessage as PlanarGeneralWcsActionBO;//Wcs的动作报文
            //var plcStateBo = plcStateMassge as PlcOnLineStateBO;//Plc在线离线报文 没有设备信息

            ////1. 验证plc是否在线
            //if (plcStateBo.PlcState == 0)
            //{
            //    var plcConnection = _PlcConnectionPool.S7GetWritePlcConnection(plcStateBo.PlcConnectionID);
            //    _LogUtil.Info($"到达DO(ArriveDoNoTaskCodeService.ProcessActionMessageAsync)处理失败：设备({plcMessage.EquipmentCode})，PLC({plcConnection?.IP ?? plcStateBo.PlcConnectionID.ToString()})已离线");

            //    return;
            //}

            //2. 验证设备是否报警
            //var plannerStateBo = planarEquipmentDbObject.bytesObjectBases.Find(o => o.ObjectType.Contains("StateBO")) as PlanarStateBO;
            //if (plannerStateBo == null)
            //{
            //    _LogUtil.Info($"到达DO(ArriveDoNoTaskCodeService.ProcessActionMessageAsync)处理失败：设备({plcMessage.EquipmentCode})没有获取到状态报文");

            //    return;
            //}

            //if (plannerStateBo.AlarmCode != 0)
            //{
            //    _LogUtil.Info($"到达DO(ArriveDoNoTaskCodeService.ProcessActionMessageAsync)处理失败：设备({plcMessage.EquipmentCode})报警,报警代码：{plannerStateBo.AlarmCode}");

            //    return;
            //}
            //3. 验证wcs任务，验证wcs当前子任务
            var exp = Expressionable.Create<WorkTaskInfo>();
            exp.AndIF(true, it => it.TaskState == EnumTaskState.Executing && 
            it.CurrentDetailTaskState == EnumDetailTaskState.Init && 
            it.CurrentFromEquipment == plcMessage.EquipmentCode &&
            it.TaskProcessState == EnumTaskProcessState.ScUnloaded);
            var taskList = await _WorkTaskInfoRepository.GetListAsync(exp.ToExpression());

            if (taskList.Count <= 0)
            {
                _LogUtil.Info($"到达DO(ArriveDoNoTaskCodeService.ProcessActionMessageAsync)处理失败：设备({plcMessage.EquipmentCode})没有待执行的任务数据");

                return;
            }

            if (taskList.Count > 1)
            {
                _LogUtil.Info($"到达DO(ArriveDoNoTaskCodeService.ProcessActionMessageAsync)处理失败：设备({plcMessage.EquipmentCode})待执行的任务数据异常");

                return;
            }

            var task = taskList.First();
            //未执行（待执行）
            //4. 组织报文，写入plc
            var objectType = typeof(PlanarGeneralWriteWcsAction).Name;
            var writeConfig = await _PlcWriteDbInfoRepository.GetFirstAsync(it => it.EquipmentCode == plcMessage.EquipmentCode && it.ObjectType == objectType);
            if (writeConfig == null)
            {
                _LogUtil.Info($"到达DO(ArriveDoNoTaskCodeService.ProcessActionMessageAsync)处理失败：设备({plcMessage.EquipmentCode})获取PLC写入配置失败");

                return;
            }

            //plc报文什么握手类型则回什么握手类型
            PlanarGeneralWriteWcsAction writeBo = new PlanarGeneralWriteWcsAction(
                writeConfig.PlcConnectionId,
                writeConfig.ID,
                writeConfig.DbCode,
                writeConfig.DbStart,
                objectType,
                writeConfig.EquipmentCode.ToInt32(),
                plcMessage.ActionType,
                task.CurrentToEquipment.ToInt32(),
                task.TaskCode,
                task.PalletCode,
                plcMessage.PalletType,
                alrmCode: plcMessage.AlrmCode);

            var plcConn = _PlcConnectionPool.S7GetWritePlcConnection(writeBo.PlcConnectionID);
            if (plcConn == null)
            {
                _LogUtil.Info($"到达DO(ArriveDoNoTaskCodeService.ProcessActionMessageAsync)处理失败：设备({writeBo.EquipmentCode})获取连接({writeBo.PlcConnectionID})失败");

                return;
            }

            var writeResult = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
            if (writeResult == false)
            {
                _LogUtil.Info($"到达DO(ArriveDoNoTaskCodeService.ProcessActionMessageAsync)处理失败：PLC(IP{plcConn.IP},设备{writeBo.EquipmentCode})写入报文失败");

                return;
            }

            //5.写入成功，结束任务，上报wms
            task.TaskState = EnumTaskState.Finish;
            task.UpdateTime = DateTime.Now;
            task.CurrentDetailTaskState = EnumDetailTaskState.Finish;
            task.CurrentUpdateTime = DateTime.Now;
            task.TaskProcessState = EnumTaskProcessState.ScUnloaded;

            WMSApiDomain.WebApi.HeaderResult<bool> uploadResult = new();
            try
            {
                uploadResult = await WCSMessageWithWMSApi.WCSNoticeTaskAutoCompleteAsync(task.WmsTaskCode, plcMessage.PalletBarcode, plcMessage.EquipmentCode);
                if (uploadResult.IsSucceed)
                {
                    task.UploadWmsState = EnumUploadWmsState.Succeed;
                }
                else
                {
                    task.UploadWmsState = EnumUploadWmsState.Failed;
                }
                task.UploadWmsTime = DateTime.Now;
            }
            catch (Exception ex)
            {
                _LogUtil.Info($"到达DO完成任务(ArriveDoFinishTaskService.ProcessActionMessageAsync)上传WMS异常：设备{writeBo.EquipmentCode}),任务号{task.TaskCode}上传WMS异常，异常信息：{ex.Message}");
            }

            await _WorkTaskInfoRepository.UpdateAsync(task);

            _LogUtil.Info($"到达DO(ArriveDoNoTaskCodeService.ProcessActionMessageAsync)处理成功：PLC(IP{plcConn.IP},设备{plcMessage.EquipmentCode})");
        }
    }
}
